<script setup lang="ts">
import {onBeforeUnmount, onMounted, ref, toRaw} from 'vue'
import EditDialog from "./components/EditDialog.vue";
import {OtpRecord} from "./type.ts";
import * as OTPAuth from "otpauth";
import InputInlineEditor from "./components/InputInlineEditor.vue";
import jsQR from "jsqr";
import {clone, cloneDeep} from "lodash-es";
import {Dialog} from "./lib/dialog.ts";

const editDialog = ref<InstanceType<typeof EditDialog> | null>(null)
const records = ref<OtpRecord[]>([])
let doc: DbDoc | null = null

let updateImer: any = null

onMounted(() => {
    updateImer = setInterval(() => {
        records.value.forEach((r, index) => {
            if (!r.runtime) {
                r.runtime = {
                    code: '',
                    remain: 0,
                }
            }
            let totp = new OTPAuth.TOTP({
                algorithm: "SHA1",
                digits: 6,
                period: r.period,
                secret: r.secret,
                //   or: `OTPAuth.Secret.fromBase32("US3WHSG7X5KAPV27VANWKQHF3SH3HULL")`
                //   or: `new OTPAuth.Secret()`
            });
            const now = Math.floor(Date.now() / 1000)
            r.runtime.remain = r.period - now % r.period
            r.runtime.code = totp.generate()
        })
    }, 1000)
})
onBeforeUnmount(() => {
    clearInterval(updateImer)
})

const sync = () => {
    let data = cloneDeep(toRaw(records.value))
    data = data.filter(r => {
        // @ts-ignore
        delete r.runtime
        return true
    })
    if (!doc) {
        doc = {
            _id: 'records',
        }
    }
    doc.data = data
    if (window.focusany) {
        const ret = window.focusany.db.put(doc)
        if (!ret.ok) {
            Dialog.tipError('更新失败')
        } else {
            doc._rev = ret.rev
        }
    }
}

const doAdd = (data: OtpRecord) => {
    records.value.push(clone(data))
    sync()
}

const imageQrcodeRecognize = async (data: string) => {
    return new Promise((resolve, reject) => {
        const canvas = document.createElement('canvas');
        const ctx: any = canvas.getContext("2d");
        const img = new Image()
        img.onload = () => {
            canvas.width = img.width;
            canvas.height = img.height;
            ctx.drawImage(img, 0, 0, img.width, img.height);
            const imageData = ctx.getImageData(0, 0, img.width, img.height).data
            const result = jsQR(imageData, img.width, img.height, {
                inversionAttempts: "dontInvert"
            });
            if (result && result.data) {
                resolve(result.data)
            } else {
                reject('未识别到二维码')
            }
        }
        img.src = data
    })
}

const doAddFromQrcode = async () => {
    focusany.screenCapture(async (data) => {
        if (!data) {
            return
        }
        try {
            const result = await imageQrcodeRecognize(data)
            const url = new URL(result as any)
            const secret = url.searchParams.get('secret')
            const issuer = url.searchParams.get('issuer')
            const period = 30
            doAdd({
                title: issuer || '未命名',
                secret,
                period
            } as OtpRecord)
        } catch (e) {
            Dialog.tipError(e as any)
            return
        }
    })
}
const doEditTitle = (index: number, value: string) => {
    records.value[index].title = value
    sync()
}
const doCopy = (index: number) => {
    const record = records.value[index]
    focusany.copyText(record.runtime?.code)
    focusany.showToast(`已复制 ${record.runtime?.code}`)
}
const doDelete = (index: number) => {
    Dialog.confirm('确定删除吗？', () => {
        records.value.splice(index, 1)
        sync()
    })
}
const doToTop = (index: number) => {
    const record = records.value.splice(index, 1)
    records.value.unshift(record[0])
    sync()
}

window.focusany && focusany.onPluginReady((data) => {
    doc = focusany.db.get('records')
    if (doc) {
        records.value = doc.data || []
    }
})
</script>

<template>
    <div class="border-t border-solid border-gray-300 relative"
         style="height:100vh;">
        <div class="flex h-full w-full">
            <div class="flex-grow overflow-y-auto p-5">
                <div v-for="(r,rIndex) in records" class="pb-4">
                    <div class="rounded-lg shadow border p-3 relative group h-32">
                        <div>
                            <div class="text-primary mb-2 flex">
                                <div>
                                    <icon-lock/>
                                    {{ r.title }}
                                </div>
                                <InputInlineEditor :value="r.title" @change="doEditTitle(rIndex,$event)">
                                    <div class="cursor-pointer ml-2">
                                        <icon-edit/>
                                    </div>
                                </InputInlineEditor>
                            </div>
                            <div class="text-4xl font-bold leading-10 cursor-pointer"
                                 @click="doCopy(rIndex)"
                                 v-if="r.runtime&&r.runtime.code">
                                {{ r.runtime?.code }}
                            </div>
                            <div class="text-4xl font-bold w-32 bg-gray-200 h-10 rounded-lg" v-else></div>
                        </div>
                        <div v-if="r.runtime">
                            <a-progress :percent="r.runtime.remain/r.period"
                                        :show-text="false"></a-progress>
                        </div>
                        <div v-else class="bg-gray-100 h-4 mt-2 rounded-lg"></div>
                        <div class="absolute group-hover:block hidden right-2 top-2">
                            <a-button type="text" @click="doToTop(rIndex)">
                                <template #icon>
                                    <icon-to-top/>
                                </template>
                            </a-button>
                            <a-button type="text" @click="doDelete(rIndex)">
                                <template #icon>
                                    <icon-delete/>
                                </template>
                            </a-button>
                        </div>
                    </div>
                </div>
                <div class="py-20" v-if="!records.length">
                    <a-empty description="暂无数据"/>
                </div>
            </div>
            <div class="w-48 flex-shrink-0 p-3">
                <div>
                    <a-button class="w-full mb-3"
                              type="primary"
                              @click="editDialog?.show()">
                        <template #icon>
                            <icon-plus/>
                        </template>
                        添加
                    </a-button>
                    <a-button class="w-full mb-3"
                              type="primary"
                              @click="doAddFromQrcode">
                        <template #icon>
                            <icon-qrcode/>
                        </template>
                        扫描二维码
                    </a-button>
                </div>
            </div>
        </div>
        <div class="absolute bottom-5 right-5">
            <img src="./assets/image.svg" class="w-40"/>
        </div>
    </div>
    <EditDialog ref="editDialog" @submit="doAdd"/>
</template>
